package com.pdh.service;

import com.pdh.bean.Express;
import com.pdh.bean.LazyBoardInfo;
import com.pdh.bean.Message;
import com.pdh.dao.BaseExpressDao;
import com.pdh.dao.imp.ExpressDaoMysql;
import com.pdh.exception.DuplicateCodeException;
import com.pdh.exception.DuplicateNumberException;
import com.pdh.exception.UnHandleException;
import com.pdh.util.LoggerUtil;
import com.pdh.paging.BootStrapTableExpress;
import com.pdh.paging.ResultData;
import com.pdh.util.DateFormatUtil;
import com.pdh.util.RandomUtil;

import java.util.*;
import java.util.stream.Stream;

/**
 * @Author: 彭德华
 * @Date 2021-08-29 22:19
 */
public class ExpressService {

    /**
     * 这样做的原因是：
     * 降低与数据库的耦合度 改为oracle的话只需要改为：new ExpressDaoOracle()即可
     */
    private static BaseExpressDao dao = new ExpressDaoMysql();

    /**
     * 把Express -> BootStrapTableExpress 实现代码块进行封装，多次使用到
     *
     * @param express
     * @return tableExpress
     */
    private static BootStrapTableExpress transExpressToTableExpress(Express express) {
        String inTime = DateFormatUtil.format(express.getInTime());
        String outTime = express.getOutTime() == null ? "待取件" : DateFormatUtil.format(express.getOutTime());
        String status = null;
        switch (express.getStatus()) {
            //0 审核中,1 待取件,2 已取件,3 已取消,4 已删除,5 异常
            case 0:
                status = "审核中";
                break;
            case 1:
                status = "待取件";
                break;
            case 2:
                status = "已取件";
                break;
            case 3:
                status = "已取消";
                break;
            case 4:
                status = "已删除";
                break;
            case 5:
                status = "异常";
                break;
            default:
                status = "此快递不存在";
                break;
        }
        String code = express.getCode() == null ? "已取件" : express.getCode();
        BootStrapTableExpress tableExpress = new BootStrapTableExpress(express.getId(), express.getNumber(),
                 express.getUsername(), express.getUserPhone(),express.getCompany(), code,
                inTime, outTime, status, express.getCourierPhone());
        return tableExpress;
    }

    /**
     * @return [{size:总数,day:新增},{size:总数,day:新增}]
     */
    public static Message consoleExpress() {
        Message msg = null;
        Map<String, Integer> data = dao.consoleExpress();
        if (data.size() == 0) {
            //没有数据
            msg = new Message(-1, "查找失败");
        } else {
            msg = new Message(0, "查找成功！", data);
        }
        return msg;

    }

    /**
     * @param paging 是否分页标记 true/false 分页/查询所有
     * @param offset sql语句起始索引
     * @param limit  页查询的数量
     * @return Message
     */
    public static Message findAll(boolean paging, int offset, int limit) {
        Message msg = null;
        //在此处封装数据 业务逻辑过长，就包装到service处理
        List<Express> queryList = dao.findAll(paging, offset, limit);
        //1.将集合封装为 bootstrap-table识别的格式
        List<BootStrapTableExpress> tableList = new ArrayList<>();
        if (queryList != null) {
            for (Express express : queryList) {
                BootStrapTableExpress e = transExpressToTableExpress(express);
                tableList.add(e);
            }
            Integer total = dao.consoleExpress().get("expressTotal");//expressTotal表示快件总数
            //将集合封装为bootstrap-table识别的格式
            ResultData<BootStrapTableExpress> data = new ResultData<>(tableList, total);
            msg = new Message(0, "查询成功", data);
        } else {
            msg = new Message(-1, "查询失败或数据为空");
        }
        return msg;
    }

    /**
     * @param number 单号
     * @return 查询的快递信息，单号不存在时候返回null
     */
    public static Message findByNumber(String number) {
        Express e = dao.findByNumber(number);
        Message msg = null;
        if (e == null) {
            msg = new Message(-1, "单号不存在");
        } else {
            msg = new Message(0, "查询成功", e);
        }
        return msg;
    }

    /**
     * @param code 取件码
     * @return 查询的快递信息，取件码不存在时候返回null
     */
    public static Message findByCode(String code) {
        Express e = dao.findByCode(code);
        Message msg = null;
        if (e == null) {
            msg = new Message(-1, "取件码不存在");
        } else {
            BootStrapTableExpress tableExpress = transExpressToTableExpress(e);
            msg = new Message(0, "查询成功", tableExpress);
        }
        return msg;
    }

    /**
     * @param userPhone 用户手机号码
     * @return 查询的快递信息列表 把map存储为Message的data
     * 以map键值对存储，key表示不同的状态，value表示对应状态的List<BootStrapTableExpress>类对应的表
     * 借助Stream流处理数据，非常的高效，不明白的地方查看一下资料把，这种方式（分类+排序）处理数据的是真的快。
     */
    public static Message findByUserPhone(String userPhone) {
        List<Express> list = dao.findByUserPhone(userPhone);
        Message msg = null;
        if (list.size() == 0) {
            msg = new Message(-1, "此号码快递为空");
        } else {
            //这里要封装快递
            List<BootStrapTableExpress> tableList = new ArrayList<>();//封装成能直接返回到前端的数据
            //1.遍历数据，把数据格式化
            for (Express e : list) {
                BootStrapTableExpress tableExpress = transExpressToTableExpress(e);
                tableList.add(tableExpress);
            }
            /**
             * 2.对数据进行分类+排序（把数据分为待取件、已取件和其他状态三个流），用到Stream流
             *  Stream流中：
             *      filter()方法根据需求过滤掉数据。其中的条件使用lambda表达式表示
             *      sorted()方法根据排序条件进行排序
             *
             * status:
             *      0 审核中,1 待取件,2 已取件,3 已取消,4 已删除,5 异常
             */
            //1.待取件
            Stream<BootStrapTableExpress> status1List = tableList.stream().filter(tableExpress -> {
                if (tableExpress.getStatus().equals("待取件")) {//true 保留
                    return true;
                } else {//false 舍去
                    return false;
                }
            }).sorted((o1, o2) -> {//选择按时间排序 先大后小，先新后旧s
                long o1Time = DateFormatUtil.toTime(o1.getInTime());
                long o2Time = DateFormatUtil.toTime(o2.getInTime());
                return (int) (o1Time - o2Time);
            });

            //2.已取件
            Stream<BootStrapTableExpress> status2List = tableList.stream().filter(tableExpress -> {
                if (tableExpress.getStatus().equals("已取件")) {//true 保留
                    return true;
                } else {//false 舍去
                    return false;
                }
            }).sorted((o1, o2) -> {//选择按时间排序 先大后小，先新后旧s
                long o1Time = DateFormatUtil.toTime(o1.getInTime());
                long o2Time = DateFormatUtil.toTime(o2.getInTime());
                return (int) (o1Time - o2Time);
            });

            //3.除了以取件和待取件的快递 status3List
            Stream<BootStrapTableExpress> status3List = tableList.stream().filter(tableExpress -> {
                if (tableExpress.getStatus().matches(".取件$")) {//reg匹配 除了已取件和待取件的数据
                    return false;
                } else {
                    return true;
                }
            }).sorted((o1, o2) -> {//选择按时间排序 先大后小，先新后旧s
                long o1Time = DateFormatUtil.toTime(o1.getInTime());
                long o2Time = DateFormatUtil.toTime(o2.getInTime());
                return (int) (o1Time - o2Time);
            });

            Map<String,Object[]> data = new HashMap<>();
            //把流变为数组，更加容易操作
            Object[] status1=status1List.toArray();
            Object[] status2 =status2List.toArray();
            Object[] status3 =status3List.toArray();

            data.put("status1List", status1);
            data.put("status2List", status2);
            data.put("status3List", status3);

            msg = new Message(0, "查询成功", data);
        }
        return msg;
    }

    /**
     * @param userPhone 用户手机号码
     * @param status    指定的状态码
     * @return 查询的快递信息列表，不存在时候返回null
     */
    public static Message findByUserPhoneAndStatus(String userPhone, int status) {
        List<Express> list = dao.findByUserPhoneAndStatus(userPhone, status);
        Message msg = null;
        if (list.size() == 0) {
            //未查到快递信息
            msg = new Message(-1, "未查询到快递信息");
        } else {
            List<BootStrapTableExpress> tableList = new ArrayList<>();
            for (Express e : list) {
                BootStrapTableExpress tableExpress = transExpressToTableExpress(e);
                tableList.add(tableExpress);
            }
            msg = new Message(0, "查询成功", list);
        }
        return msg;
    }

    /**
     * @param sysPhone 录入人手机号码
     * @return 查询的快递信息列表，不存在时候返回null
     */
    public static Message findByCourierPhone(String sysPhone) {
        List<Express> list = dao.findByCourierPhone(sysPhone);
        Message msg = null;
        if (list == null) {
            msg = new Message(-1, "该快递员没有录入的快递");
        } else {
            List<BootStrapTableExpress> tableList = new ArrayList<>();
            for (Express e : list) {
                BootStrapTableExpress tableExpress = transExpressToTableExpress(e);
                tableList.add(tableExpress);
            }
            msg = new Message(0, "查询成功", tableList);
        }
        return msg;
    }

    /**
     * @param express 录入的快递对象
     * @return 录入结果 true/false 成功/失败
     */
    public static Message insert(Express express) {
        //0.返回的Message
        Message msg = null;
        //1.生成并设置取件码
        express.setCode(RandomUtil.getCode() + "");//巧妙转化为字符串
        try {
            boolean flag = dao.insert(express);
            //录入成功
            if (flag == true) {
                msg = new Message(0, "快递录入成功");
                //发送短信 进行测试需要重新生成ExpressService类的测试类
                //SMSUtil.send(express.getUser_phone(), express.getCode());
                // 阿里云签名不通过，就希望把数据打印到日志即可
                LoggerUtil.getLogger(ExpressService.class).info("电话号:" + express.getUserPhone() + ",取件码:" + express.getCode());
            }
            return msg;
        } catch (DuplicateCodeException | DuplicateNumberException e) {
            if (e instanceof DuplicateCodeException) {
                //递归 因为取件码code重复，重新执行插入操作
                return ExpressService.insert(express);//DuplicateCodeException此异常是code重复异常，那么再次执行插入操作即可
            } else if (e instanceof DuplicateNumberException) {
                msg = new Message(-3, "快递单号重复,请检查单号");
                //因为是快递单号重复，需要提示用户再次输入正确的快递单号
            } else {//UnHandleException
                msg = new Message(-1, "未知异常");
                LoggerUtil.getLogger(ExpressService.class).error(e.getMessage());
            }
        }
        return msg;
    }

    /**
     * @param id         要修改的快递id
     * @param newExpress 新的快递对象(number,company,username,userPhone)
     * @return 修改结果 true/false 成功/失败
     * 更新操作可更新number，则此number存在重复的问题，需要做异常处理
     */
    public static Message update(int id, Express newExpress) {
        //0.返回的Message
        Message msg = null;
        try {
            boolean flag = dao.update(id, newExpress);
            //录入成功
            if (flag == true) {
                msg = new Message(0, "快递修改成功");
                //发送短信
                //SMSUtil.send(express.getUser_phone(), express.getCode());
                // 阿里云签名不通过，就希望把数据打印到日志即可
                System.out.println("电话号:" + newExpress.getUserPhone() + ",取件码:" + newExpress.getCode());
                //看看怎么处理使得它打印到日志即可
            } else {
                msg = new Message(-1, "快递修改失败");
            }
            return msg;
        } catch (Exception e) {
            if (e instanceof DuplicateNumberException) {
                msg = new Message(-3, "快递单号重复,请检查单号");
                //因为是快递单号重复，需要提示用户再次输入正确的快递单号
            } else {
                msg = new Message(-1, "未知异常");
                LoggerUtil.getLogger(ExpressService.class).error(e.getMessage());
            }
        }
        return msg;
    }

    /**
     * @param code 要修改的取件码 2表示以取件
     * @return true/false 成功/失败
     */
    public static Message updateStatus(String code, int status) {
        boolean flag = dao.updateStatus(code, status);
        Message msg = null;
        if (flag) {
            msg = new Message(0, "快递状态更新成功");
        } else {
            msg = new Message(-1, "取件码不存在,请用户更新取件码");
        }
        return msg;
    }

    /**
     * @param id 要删除的快递id
     * @return true/false 成功/失败
     */
    public static Message delete(int id) {
        boolean flag = dao.delete(id);
        Message msg = null;
        if (flag) {
            msg = new Message(0, "删除成功");
        } else {
            msg = new Message(-1, "删除失败");
        }
        return msg;
    }

    /**
     * 于查询总懒人排行榜 包括总榜、年榜、月榜
     * lazyBoardCount,lazyBoardYear,lazyBoardMonth
     *
     * @param no     0-count 1-year 2-month
     * @param paging
     * @param offset
     * @param limit
     * @return
     */
    public static Message lazyBoardInfo(int no, boolean paging, int offset, int limit) {
        Message msg = null;
        Map<String, List<LazyBoardInfo>> queryMap = new HashMap<>();
        List<LazyBoardInfo> queryList = null;
        ResultData<LazyBoardInfo> data = null;
        try {
            queryMap = dao.lazyBoardInfo(paging, offset, limit);
            Integer total = (Integer) ((Map) UserService.consoleUser().getData()).get("userCount");
            switch (no) {
                case 0:
                    queryList = queryMap.get("lazyBoardCount");
                    break;
                case 1:
                    queryList = queryMap.get("lazyBoardYear");
                    break;
                case 2:
                    queryList = queryMap.get("lazyBoardMonth");
                    break;
                default:break;
            }
            data = new ResultData<>(queryList, total);
            if (data != null) {
                msg = new Message(0, "查询成功", data);
            } else {
                msg = new Message(-1, "查询失败");
            }
        } catch (UnHandleException e) {
            msg = new Message(-1, "查询失败,未知异常");
            LoggerUtil.getLogger(UserService.class).error(e.getMessage());
        }
        return msg;
    }
}
